/**
 * Copyright (c) 2021 OceanBase
 * OceanBase CE is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#define USING_LOG_PREFIX SQL_REWRITE

#include "sql/rewrite/ob_expand_aggregate_utils.h"
#include "common/ob_common_utility.h"
#include "lib/allocator/ob_allocator.h"
#include "lib/oblog/ob_log_module.h"
#include "share/ob_errno.h"
#include "share/schema/ob_table_schema.h"
#include "sql/resolver/expr/ob_raw_expr.h"
#include "sql/resolver/ob_resolver_utils.h"
#include "common/ob_common_utility.h"
#include "sql/resolver/dml/ob_select_stmt.h"
#include "sql/resolver/dml/ob_dml_stmt.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "sql/rewrite/ob_stmt_comparer.h"
#include "sql/rewrite/ob_transform_utils.h"
#include "sql/optimizer/ob_optimizer_util.h"
#include "sql/rewrite/ob_transform_rule.h"

namespace oceanbase {
using namespace common;
using namespace share::schema;
namespace sql {

int ObExpandAggregateUtils::expand_aggr_expr(ObDMLStmt* stmt, ObTransformerCtx* ctx, bool& trans_happened)
{
  int ret = OB_SUCCESS;
  ObSEArray<ObRawExpr*, 4> candi_aggr_items;
  ObSEArray<ObRawExpr*, 4> replace_exprs;
  ObSEArray<ObAggFunRawExpr*, 4> new_aggr_items;
  trans_happened = false;
  if (OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(stmt));
  } else if (OB_FAIL(extract_candi_aggr(stmt, candi_aggr_items, new_aggr_items))) {
    LOG_WARN("failed to extact candi aggr", K(ret));
  } else if (candi_aggr_items.empty()) {
    /*do nothing */
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < candi_aggr_items.count(); ++i) {
      ObRawExpr* replace_expr = NULL;
      ObAggFunRawExpr* aggr_expr = static_cast<ObAggFunRawExpr*>(candi_aggr_items.at(i));
      if (OB_ISNULL(aggr_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret), K(aggr_expr));
      } else if (is_covar_expr_type(aggr_expr->get_expr_type()) &&
                 OB_FAIL(expand_covar_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand covar expr", K(ret));
      } else if (aggr_expr->get_expr_type() == T_FUN_CORR &&
                 OB_FAIL(expand_corr_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand corr expr", K(ret));
      } else if (is_var_expr_type(aggr_expr->get_expr_type()) &&
                 OB_FAIL(expand_var_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand var expr", K(ret));
      } else if (is_regr_expr_type(aggr_expr->get_expr_type()) &&
                 OB_FAIL(expand_regr_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand regr expr", K(ret));
      } else if (is_keep_aggr_type(aggr_expr->get_expr_type()) &&
                 OB_FAIL(expand_keep_aggr_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand keep aggr expr", K(ret));
      } else if (is_common_aggr_type(aggr_expr->get_expr_type()) &&
                 OB_FAIL(expand_common_aggr_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand common aggr expr", K(ret));
      } else if (OB_ISNULL(replace_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected error", K(ret), K(replace_expr), K(aggr_expr->get_expr_type()));
      } else if (OB_FAIL(replace_expr->formalize(ctx->session_info_))) {
        LOG_WARN("failed to formalize", K(ret));
      } else if (aggr_expr->get_result_type() != replace_expr->get_result_type() &&
                 OB_FAIL(add_cast_expr(ctx, replace_expr, aggr_expr->get_result_type(), replace_expr))) {
        LOG_WARN("failed to add cast expr", K(ret));
      } else if (OB_FAIL(replace_expr->pull_relation_id_and_levels(stmt->get_current_level()))) {
        LOG_WARN("failed to pull relation id and levels", K(ret));
      } else if (OB_FAIL(replace_exprs.push_back(replace_expr))) {
        LOG_WARN("failed to push back expr", K(ret));
      } else { /*do nothing*/
      }
    }
    if (OB_SUCC(ret)) {
      if (stmt->is_select_stmt() &&
          OB_FAIL(static_cast<ObSelectStmt*>(stmt)->get_aggr_items().assign(new_aggr_items))) {
        LOG_WARN("failed to assign expr", K(ret));
      } else if (!stmt->is_select_stmt() &&
                 OB_FAIL(static_cast<ObDelUpdStmt*>(stmt)->get_returning_aggr_items().assign(new_aggr_items))) {
        LOG_WARN("failed to assign expr", K(ret));
      } else if (OB_FAIL(stmt->replace_inner_stmt_expr(candi_aggr_items, replace_exprs))) {
        LOG_WARN("failed to replace stmt expr", K(ret));
      } else {
        trans_happened = true;
      }
    }
  }
  return ret;
}

int ObExpandAggregateUtils::expand_window_aggr_expr(ObDMLStmt* stmt, ObTransformerCtx* ctx, bool& trans_happened)
{
  int ret = OB_SUCCESS;
  ObSEArray<ObRawExpr*, 4> candi_win_items;
  ObSEArray<ObAggFunRawExpr*, 4> new_aggr_items;
  ObSEArray<ObRawExpr*, 4> replace_exprs;
  ObSEArray<ObWinFunRawExpr*, 4> new_win_exprs;
  trans_happened = false;
  if (OB_ISNULL(stmt) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("table item is null", K(ret), K(stmt), K(ctx));
  } else if (!stmt->is_select_stmt()) {
    /*do nothing*/
  } else if (OB_FAIL(extract_candi_window_aggr(static_cast<ObSelectStmt*>(stmt), candi_win_items, new_win_exprs))) {
    LOG_WARN("failed to extract candi window aggr", K(ret));
  } else if (candi_win_items.empty()) {
    /*do nothing */
  } else {
    ObSelectStmt* select_stmt = static_cast<ObSelectStmt*>(stmt);
    for (int64_t i = 0; OB_SUCC(ret) && i < candi_win_items.count(); ++i) {
      ObRawExpr* replace_expr = NULL;
      ObWinFunRawExpr* win_expr = static_cast<ObWinFunRawExpr*>(candi_win_items.at(i));
      if (OB_ISNULL(win_expr) || OB_ISNULL(win_expr->get_agg_expr())) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret), K(win_expr));
      } else if (is_covar_expr_type(win_expr->get_agg_expr()->get_expr_type()) &&
                 OB_FAIL(expand_covar_expr(ctx, win_expr->get_agg_expr(), replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand covar expr", K(ret));
      } else if (win_expr->get_agg_expr()->get_expr_type() == T_FUN_CORR &&
                 OB_FAIL(expand_corr_expr(ctx, win_expr->get_agg_expr(), replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand corr expr", K(ret));
      } else if (is_var_expr_type(win_expr->get_agg_expr()->get_expr_type()) &&
                 OB_FAIL(expand_var_expr(ctx, win_expr->get_agg_expr(), replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand var expr", K(ret));
      } else if (is_regr_expr_type(win_expr->get_agg_expr()->get_expr_type()) &&
                 OB_FAIL(expand_regr_expr(ctx, win_expr->get_agg_expr(), replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand regr exprs", K(ret));
      } else if (is_keep_aggr_type(win_expr->get_agg_expr()->get_expr_type()) &&
                 OB_FAIL(expand_keep_aggr_expr(ctx, win_expr->get_agg_expr(), replace_expr, new_aggr_items))) {
        LOG_WARN("failed to expand keep aggr exprs", K(ret));
      } else if (is_common_aggr_type(win_expr->get_agg_expr()->get_expr_type()) &&
                 OB_FAIL(expand_common_aggr_expr(ctx, win_expr->get_agg_expr(), replace_expr, new_aggr_items))) {
        LOG_WARN("failed to common aggr exprs", K(ret));
      } else if (OB_ISNULL(replace_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected error", K(ret), K(replace_expr), K(win_expr->get_agg_expr()->get_expr_type()));
      } else if (OB_FAIL(replace_expr->formalize(ctx->session_info_))) {
        LOG_WARN("failed to formalize", K(ret));
      } else if (win_expr->get_agg_expr()->get_result_type() != replace_expr->get_result_type() &&
                 OB_FAIL(add_cast_expr(ctx, replace_expr, win_expr->get_agg_expr()->get_result_type(), replace_expr))) {
        LOG_WARN("failed to add cast expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::process_window_complex_agg_expr(
                     *ctx->expr_factory_, replace_expr->get_expr_type(), win_expr, replace_expr, &new_win_exprs))) {
        LOG_WARN("failed to process window complex agg expr", K(ret));
      } else if (replace_expr->is_aggr_expr() &&
                 OB_FAIL(replace_exprs.push_back(new_win_exprs.at(new_win_exprs.count() - 1)))) {
        LOG_WARN("failed to push back expr", K(ret));
      } else if (!replace_expr->is_aggr_expr() && OB_FAIL(replace_exprs.push_back(replace_expr))) {
        LOG_WARN("failed to push back expr", K(ret));
      } else { /*do nothing*/
      }
    }
    if (OB_SUCC(ret)) {
      if (OB_FAIL(add_win_exprs(select_stmt, replace_exprs, new_win_exprs))) {
        LOG_WARN("failed to win exprs", K(ret));
      } else if (OB_FAIL(select_stmt->replace_inner_stmt_expr(candi_win_items, replace_exprs))) {
        LOG_WARN("failed to replace stmt expr");
      } else {
        trans_happened = true;
      }
    }
  }
  return ret;
}
int ObExpandAggregateUtils::add_linear_inter_expr(ObDMLStmt* stmt, ObTransformerCtx* ctx, bool& trans_happened)
{
  int ret = OB_SUCCESS;
  ObSEArray<ObAggFunRawExpr*, 4> aggr_exprs;
  ObSEArray<ObWinFunRawExpr*, 4> win_exprs;
  trans_happened = false;
  if (OB_ISNULL(stmt) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("table item is null", K(ret), K(stmt), K(ctx));
  } else if (!ctx->session_info_->use_static_typing_engine()) {
    /* do nothing*/
  } else if (stmt->is_select_stmt() &&
             OB_FAIL(append(aggr_exprs, static_cast<ObSelectStmt*>(stmt)->get_aggr_items()))) {
    LOG_WARN("failed to append aggr exprs", K(ret));
  } else if (stmt->is_select_stmt() &&
             OB_FAIL(append(win_exprs, static_cast<ObSelectStmt*>(stmt)->get_window_func_exprs()))) {
    LOG_WARN("failed to append win exprs", K(ret));
  } else if ((stmt->is_delete_stmt() || stmt->is_update_stmt() || stmt->is_merge_stmt() || stmt->is_insert_stmt()) &&
             OB_FAIL(append(aggr_exprs, static_cast<ObDelUpdStmt*>(stmt)->get_returning_aggr_items()))) {
    LOG_WARN("failed to append aggr exprs", K(ret));
  } else {
    for (int64_t i = 0; OB_SUCC(ret) && i < aggr_exprs.count(); ++i) {
      if (OB_ISNULL(aggr_exprs.at(i))) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret), K(aggr_exprs.at(i)));
      } else if (!is_medain_percentile_aggr_type(aggr_exprs.at(i)->get_expr_type())) {
        /* do nothing */
      } else if (OB_FAIL(add_linear_inter_expr(ctx, aggr_exprs.at(i)))) {
        LOG_WARN("failed to add linear inter expr", K(ret), K(aggr_exprs.at(i)));
      } else {
        trans_happened = true;
      }
    }
    for (int64_t i = 0; OB_SUCC(ret) && i < win_exprs.count(); ++i) {
      ObWinFunRawExpr* win_expr = win_exprs.at(i);
      ObAggFunRawExpr* aggr_expr = NULL;
      if (OB_ISNULL(win_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret), K(win_expr));
      } else if (OB_ISNULL(aggr_expr = win_expr->get_agg_expr()) ||
                 !is_medain_percentile_aggr_type(aggr_expr->get_expr_type())) {
        /* do nothing */
      } else if (OB_FAIL(add_linear_inter_expr(ctx, aggr_expr))) {
        LOG_WARN("failed to add linear inter expr", K(ret), K(aggr_expr));
      } else {
        trans_happened = true;
      }
    }
  }
  return ret;
}

int ObExpandAggregateUtils::add_linear_inter_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr)
{
  int ret = OB_SUCCESS;
  ObRawExpr* obj_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(
          T_FUN_MEDIAN != aggr_expr->get_expr_type() && T_FUN_GROUP_PERCENTILE_CONT != aggr_expr->get_expr_type()) ||
      OB_UNLIKELY(1 != aggr_expr->get_real_param_exprs().count() || 1 != aggr_expr->get_order_items().count()) ||
      OB_ISNULL(obj_expr = aggr_expr->get_order_items().at(0).expr_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else if (OB_NOT_NULL(aggr_expr->get_linear_inter_expr())) {
    /* do nothing */
  } else {
    ObRawExpr* minus_expr = NULL;
    ObRawExpr* mul_expr = NULL;
    ObRawExpr* add_expr = NULL;
    ObVarRawExpr* right_expr = NULL;
    ObVarRawExpr* left_expr = NULL;
    ObVarRawExpr* factor_expr = NULL;
    const ObExprResType& obj_result_type = obj_expr->get_result_type();
    ObExprResType factor_result_type(*ctx->allocator_);
    factor_result_type.set_number();
    factor_result_type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE][ObNumberType].get_scale());
    factor_result_type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE][ObNumberType].get_precision());
    if (OB_FAIL(ObRawExprUtils::build_variable_expr(*ctx->expr_factory_, obj_result_type, right_expr))) {
      LOG_WARN("failed to build const empty op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_variable_expr(*ctx->expr_factory_, obj_result_type, left_expr))) {
      LOG_WARN("failed to build const empty op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_variable_expr(*ctx->expr_factory_, factor_result_type, factor_expr))) {
      LOG_WARN("failed to build const empty op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MINUS, right_expr, left_expr, minus_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MUL, factor_expr, minus_expr, mul_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_ADD, mul_expr, left_expr, add_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(add_expr->formalize(ctx->session_info_))) {
      LOG_WARN("formalize linear inter expr failed", K(ret));
    } else {
      aggr_expr->set_linear_inter_expr(add_expr);
    }
  }
  return ret;
}

// Premise: (expr1, expr2) neither expr is NULL
// T_FUN_COVAR_POP == node->type_: (SUM(expr1 * expr2) - SUM(expr2) * SUM(expr1) / count(expr1 * expr2)) / count(expr1 *
// expr2) T_FUN_COVAR_SAMP== node->type_: (SUM(expr1 * expr2) - SUM(expr1) * SUM(expr2) / count(expr1 * expr2)) /
// (count(expr1 * expr2)-1)
int ObExpandAggregateUtils::expand_covar_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr1 = NULL;
  ObRawExpr* parma_expr2 = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(!is_covar_expr_type(aggr_expr->get_expr_type()) || aggr_expr->get_real_param_exprs().count() != 2) ||
      OB_ISNULL(parma_expr1 = aggr_expr->get_real_param_exprs().at(0)) ||
      OB_ISNULL(parma_expr2 = aggr_expr->get_real_param_exprs().at(1))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObRawExpr* case_when_expr1 = NULL;
    ObRawExpr* case_when_expr2 = NULL;
    ObRawExpr* multi_expr = NULL;
    ObRawExpr* multi_sum_expr = NULL;
    ObRawExpr* and_expr = NULL;
    ObAggFunRawExpr* sum_expr1 = NULL;
    ObAggFunRawExpr* sum_expr2 = NULL;
    ObAggFunRawExpr* sum_product_expr = NULL;
    ObAggFunRawExpr* count_product_expr = NULL;
    ObRawExpr* div_expr = NULL;
    ObRawExpr* minus_expr = NULL;
    ObRawExpr* div_sum_expr = NULL;
    if (OB_FAIL(build_special_case_when_expr(
            *ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr1, case_when_expr1))) {
      LOG_WARN("failed to build special case when expr", K(ret));
    } else if (OB_FAIL(build_special_case_when_expr(
                   *ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr2, case_when_expr2))) {
      LOG_WARN("failed to build special case when expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MUL, parma_expr1, parma_expr2, multi_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, case_when_expr1, sum_expr1))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_expr1))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, case_when_expr2, sum_expr2))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_expr2))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MUL, sum_expr1, sum_expr2, multi_sum_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, multi_expr, sum_product_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_product_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, multi_expr, count_product_expr))) {
      LOG_WARN("failed to build count expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, count_product_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_DIV, multi_sum_expr, count_product_expr, div_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MINUS, sum_product_expr, div_expr, minus_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (aggr_expr->get_expr_type() == T_FUN_COVAR_POP) {
      if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
              *ctx->expr_factory_, T_OP_DIV, minus_expr, count_product_expr, div_sum_expr))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else {
        sum_expr1->set_expr_level(aggr_expr->get_expr_level());
        sum_expr2->set_expr_level(aggr_expr->get_expr_level());
        sum_product_expr->set_expr_level(aggr_expr->get_expr_level());
        count_product_expr->set_expr_level(aggr_expr->get_expr_level());
        replace_expr = div_sum_expr;
      }
    } else {
      ObRawExpr* null_expr = NULL;
      ObConstRawExpr* one_expr = NULL;
      ObConstRawExpr* zero_expr = NULL;
      ObRawExpr* minus_expr2 = NULL;
      ObRawExpr* ne_expr = NULL;
      ObRawExpr* case_when_expr = NULL;
      if (OB_FAIL(ObRawExprUtils::build_null_expr(*ctx->expr_factory_, null_expr))) {
        LOG_WARN("failed to build null expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx->expr_factory_, ObIntType, 1, one_expr))) {
        LOG_WARN("failed to build const int expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx->expr_factory_, ObIntType, 0, zero_expr))) {
        LOG_WARN("failed to build const int expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_MINUS, count_product_expr, one_expr, minus_expr2))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_NE, minus_expr2, zero_expr, ne_expr))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(
                     *ctx->expr_factory_, ne_expr, minus_expr2, null_expr, case_when_expr))) {
        LOG_WARN("failed to build case when expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_DIV, minus_expr, case_when_expr, div_sum_expr))) {
        LOG_WARN("failed to common binary op expr", K(ret));
      } else {
        sum_expr1->set_expr_level(aggr_expr->get_expr_level());
        sum_expr2->set_expr_level(aggr_expr->get_expr_level());
        sum_product_expr->set_expr_level(aggr_expr->get_expr_level());
        count_product_expr->set_expr_level(aggr_expr->get_expr_level());
        replace_expr = div_sum_expr;
      }
    }
  }
  return ret;
}

// Premise: (expr1, expr2) neither expr is NULL
// COVAR_POP(expr1, expr2) / (STDDEV_POP(expr1) * STDDEV_POP(expr2))
int ObExpandAggregateUtils::expand_corr_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr1 = NULL;
  ObRawExpr* parma_expr2 = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_CORR || aggr_expr->get_real_param_exprs().count() != 2) ||
      OB_ISNULL(parma_expr1 = aggr_expr->get_real_param_exprs().at(0)) ||
      OB_ISNULL(parma_expr2 = aggr_expr->get_real_param_exprs().at(1))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected error", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* covar_pop_expr = NULL;
    ObAggFunRawExpr* stddev_pop_expr1 = NULL;
    ObAggFunRawExpr* stddev_pop_expr2 = NULL;
    ObRawExpr* null_expr = NULL;
    ObRawExpr* case_when_expr1 = NULL;
    ObRawExpr* case_when_expr2 = NULL;
    ObRawExpr* multi_stddev_expr = NULL;
    ObRawExpr* left_multi_expr = NULL;
    ObRawExpr* right_multi_expr = NULL;
    ObRawExpr* div_expr = NULL;
    ObRawExpr* left_div_expr = NULL;
    ObRawExpr* ne_expr = NULL;
    ObRawExpr* case_when_expr = NULL;
    ObConstRawExpr* zero_expr = NULL;
    if (OB_FAIL(ObRawExprUtils::build_null_expr(*ctx->expr_factory_, null_expr))) {
      LOG_WARN("failed to build null expr", K(ret));
    } else if (OB_FAIL(build_special_case_when_expr(
                   *ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr1, case_when_expr1))) {
      LOG_WARN("failed to build special case when expr", K(ret));
    } else if (OB_FAIL(build_special_case_when_expr(
                   *ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr2, case_when_expr2))) {
      LOG_WARN("failed to build special case when expr", K(ret));
    } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_STDDEV_POP, stddev_pop_expr1))) {
      LOG_WARN("create ObOpRawExpr failed", K(ret));
    } else if (OB_FAIL(stddev_pop_expr1->add_real_param_expr(case_when_expr1))) {
      LOG_WARN("fail to add param expr to agg expr", K(ret));
    } else {
      stddev_pop_expr1->set_expr_level(aggr_expr->get_expr_level());
      if (OB_FAIL(expand_stddev_pop_expr(ctx, stddev_pop_expr1, left_multi_expr, new_aggr_items))) {
        LOG_WARN("fail to expand stddev pop expr", K(ret));
      } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_STDDEV_POP, stddev_pop_expr2))) {
        LOG_WARN("create ObOpRawExpr failed", K(ret));
      } else if (OB_FAIL(stddev_pop_expr2->add_real_param_expr(case_when_expr2))) {
        LOG_WARN("fail to add param expr to agg expr", K(ret));
      } else {
        stddev_pop_expr2->set_expr_level(aggr_expr->get_expr_level());
        if (OB_FAIL(expand_stddev_pop_expr(ctx, stddev_pop_expr2, right_multi_expr, new_aggr_items))) {
          LOG_WARN("fail to expand stddev pop expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                       *ctx->expr_factory_, T_OP_MUL, left_multi_expr, right_multi_expr, multi_stddev_expr))) {
          LOG_WARN("failed to build common binary op expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx->expr_factory_, ObIntType, 0, zero_expr))) {
          LOG_WARN("failed to build const int expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                       *ctx->expr_factory_, T_OP_NE, multi_stddev_expr, zero_expr, ne_expr))) {
          LOG_WARN("failed to build common binary op expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(
                       *ctx->expr_factory_, ne_expr, multi_stddev_expr, null_expr, case_when_expr))) {
          LOG_WARN("failed to build case when expr", K(ret));
        } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_COVAR_POP, covar_pop_expr))) {
          LOG_WARN("create ObOpRawExpr failed", K(ret));
        } else if (OB_FAIL(covar_pop_expr->add_real_param_expr(parma_expr1))) {
          LOG_WARN("fail to add param expr to agg expr", K(ret));
        } else if (OB_FAIL(covar_pop_expr->add_real_param_expr(parma_expr2))) {
          LOG_WARN("fail to add param expr to agg expr", K(ret));
        } else {
          covar_pop_expr->set_expr_level(aggr_expr->get_expr_level());
          if (OB_FAIL(expand_covar_expr(ctx, covar_pop_expr, left_div_expr, new_aggr_items))) {
            LOG_WARN("failed to expand covar expr", K(ret));
          } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                         *ctx->expr_factory_, T_OP_DIV, left_div_expr, case_when_expr, div_expr))) {
            LOG_WARN("failed to build common binary op expr", K(ret));
          } else {
            replace_expr = div_expr;
          }
        }
      }
    }
  }
  return ret;
}

int ObExpandAggregateUtils::extract_candi_aggr(
    ObDMLStmt* stmt, ObIArray<ObRawExpr*>& candi_aggr_items, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(stmt));
  } else {
    ObSEArray<ObAggFunRawExpr*, 4> aggr_items;
    if (stmt->is_select_stmt() && OB_FAIL(append(aggr_items, static_cast<ObSelectStmt*>(stmt)->get_aggr_items()))) {
      LOG_WARN("failed to append aggr items", K(ret));
    } else if (!stmt->is_select_stmt() &&
               OB_FAIL(append(aggr_items, static_cast<ObDelUpdStmt*>(stmt)->get_returning_aggr_items()))) {
      LOG_WARN("failed to append aggr items", K(ret));
    } else {
      for (int64_t i = 0; OB_SUCC(ret) && i < aggr_items.count(); ++i) {
        if (OB_ISNULL(aggr_items.at(i))) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("get unexpected null", K(ret), K(aggr_items.at(i)));
        } else if (is_valid_aggr_type(aggr_items.at(i)->get_expr_type())) {
          if (OB_FAIL(candi_aggr_items.push_back(aggr_items.at(i)))) {
            LOG_WARN("failed to push back aggr items", K(ret));
          } else { /*do nothing*/
          }
        } else if (OB_FAIL(new_aggr_items.push_back(aggr_items.at(i)))) {
          LOG_WARN("failed to push back aggr items", K(ret));
        }
      }
    }
  }
  return ret;
}

int ObExpandAggregateUtils::extract_candi_window_aggr(
    ObSelectStmt* select_stmt, ObIArray<ObRawExpr*>& candi_win_items, ObIArray<ObWinFunRawExpr*>& new_win_exprs)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(select_stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(select_stmt));
  } else {
    ObIArray<ObWinFunRawExpr*>& win_exprs = select_stmt->get_window_func_exprs();
    for (int64_t i = 0; OB_SUCC(ret) && i < win_exprs.count(); ++i) {
      ObWinFunRawExpr* win_expr = win_exprs.at(i);
      if (OB_ISNULL(win_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret), K(win_expr));
      } else if (win_expr->get_agg_expr() != NULL && is_valid_aggr_type(win_expr->get_agg_expr()->get_expr_type())) {
        if (OB_FAIL(candi_win_items.push_back(win_expr))) {
          LOG_WARN("failed to push back win expr", K(ret));
        } else { /*do nothing*/
        }
      } else if (OB_FAIL(new_win_exprs.push_back(win_expr))) {
        LOG_WARN("failed to push back win expr", K(ret));
      }
    }
  }
  return ret;
}

int ObExpandAggregateUtils::add_aggr_item(ObIArray<ObAggFunRawExpr*>& new_aggr_items, ObAggFunRawExpr*& aggr_expr)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(aggr_expr)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr));
  } else {
    int64_t i = 0;
    for (; OB_SUCC(ret) && i < new_aggr_items.count(); ++i) {
      if (OB_ISNULL(new_aggr_items.at(i))) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret), K(new_aggr_items.at(i)));
      } else if (aggr_expr->same_as(*new_aggr_items.at(i))) {
        aggr_expr = new_aggr_items.at(i);
        break;
      } else { /*do nothing*/
      }
    }
    if (OB_SUCC(ret) && i == new_aggr_items.count()) {
      if (OB_FAIL(new_aggr_items.push_back(aggr_expr))) {
        LOG_WARN("failed to push back aggr expr", K(ret));
      }
    }
  }
  return ret;
}

// T_FUN_VAR_POP == node->type_: (SUM(expr*expr) - SUM(expr)* SUM(expr)/ COUNT(expr)) / COUNT(expr)
// T_FUN_VAR_SAMP== node->type_: (SUM(expr*expr) - SUM(expr)* SUM(expr)/ COUNT(expr)) / (COUNT(expr) - 1)
int ObExpandAggregateUtils::expand_var_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr, ObRawExpr*& replace_expr,
    ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(!is_var_expr_type(aggr_expr->get_expr_type()) || aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else if (share::is_mysql_mode() && aggr_expr->get_expr_type() == T_FUN_VAR_POP) {
    if (OB_FAIL(expand_mysql_variance_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand mysql variance expr", K(ret));
    } else { /*do nothing*/
    }
  } else {
    ObRawExpr* multi_expr = NULL;
    ObRawExpr* multi_sum_expr = NULL;
    ObAggFunRawExpr* sum_expr = NULL;
    ObRawExpr* cast_sum_expr = NULL;
    ObAggFunRawExpr* sum_product_expr = NULL;
    ObRawExpr* cast_sum_product_expr = NULL;
    ObAggFunRawExpr* count_expr = NULL;
    ObRawExpr* div_expr = NULL;
    ObRawExpr* minus_expr = NULL;
    ObRawExpr* div_minus_expr = NULL;
    ObExprResType dst_type;
    dst_type.set_number();
    dst_type.set_scale(ObAccuracy::MAX_ACCURACY2[MYSQL_MODE][ObNumberType].get_scale());
    dst_type.set_precision(ObAccuracy::MAX_ACCURACY2[MYSQL_MODE][ObNumberType].get_precision());
    if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
            *ctx->expr_factory_, T_OP_MUL, parma_expr, parma_expr, multi_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, parma_expr, sum_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_expr))) {
      LOG_WARN("failed to push back aggr item", K(ret));
    } else if (share::is_mysql_mode() && OB_FAIL(add_cast_expr(ctx, sum_expr, dst_type, cast_sum_expr))) {
      LOG_WARN("failed to add cast expr", K(ret));
    } else if (share::is_mysql_mode() &&
               OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MUL, cast_sum_expr, cast_sum_expr, multi_sum_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (share::is_oracle_mode() && OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                                              *ctx->expr_factory_, T_OP_MUL, sum_expr, sum_expr, multi_sum_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, multi_expr, sum_product_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_product_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (share::is_mysql_mode() &&
               OB_FAIL(add_cast_expr(ctx, sum_product_expr, dst_type, cast_sum_product_expr))) {
      LOG_WARN("failed to add cast expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, parma_expr, count_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, count_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_DIV, multi_sum_expr, count_expr, div_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (share::is_mysql_mode() &&
               OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MINUS, cast_sum_product_expr, div_expr, minus_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (share::is_oracle_mode() &&
               OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MINUS, sum_product_expr, div_expr, minus_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (aggr_expr->get_expr_type() == T_FUN_VAR_POP) {
      if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
              *ctx->expr_factory_, T_OP_DIV, minus_expr, count_expr, div_minus_expr))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else {
        sum_expr->set_expr_level(aggr_expr->get_expr_level());
        sum_product_expr->set_expr_level(aggr_expr->get_expr_level());
        count_expr->set_expr_level(aggr_expr->get_expr_level());
        replace_expr = div_minus_expr;
      }
    } else {
      ObConstRawExpr* one_expr = NULL;
      ObConstRawExpr* zero_expr = NULL;
      ObRawExpr* minus_expr2 = NULL;
      ObRawExpr* ne_expr = NULL;
      ObRawExpr* case_when_expr = NULL;
      ObRawExpr* null_expr = NULL;
      if (OB_FAIL(ObRawExprUtils::build_null_expr(*ctx->expr_factory_, null_expr))) {
        LOG_WARN("failed to build null expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx->expr_factory_, ObIntType, 1, one_expr))) {
        LOG_WARN("failed to build const int expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx->expr_factory_, ObIntType, 0, zero_expr))) {
        LOG_WARN("failed to build const int expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_MINUS, count_expr, one_expr, minus_expr2))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_NE, minus_expr2, zero_expr, ne_expr))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(
                     *ctx->expr_factory_, ne_expr, minus_expr2, null_expr, case_when_expr))) {
        LOG_WARN("failed to build case when expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_DIV, minus_expr, case_when_expr, div_minus_expr))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else {
        sum_expr->set_expr_level(aggr_expr->get_expr_level());
        sum_product_expr->set_expr_level(aggr_expr->get_expr_level());
        count_expr->set_expr_level(aggr_expr->get_expr_level());
        replace_expr = div_minus_expr;
      }
    }
  }
  return ret;
}

int ObExpandAggregateUtils::expand_regr_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(!is_regr_expr_type(aggr_expr->get_expr_type()))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else if (aggr_expr->get_expr_type() == T_FUN_REGR_SLOPE) {
    if (OB_FAIL(expand_regr_slope_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand regr slope expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_REGR_INTERCEPT) {
    if (OB_FAIL(expand_regr_intercept_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand regr intercept expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_REGR_COUNT) {
    if (OB_FAIL(expand_regr_count_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand regr count expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_REGR_R2) {
    if (OB_FAIL(expand_regr_r2_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand regr r2 expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_REGR_AVGX || aggr_expr->get_expr_type() == T_FUN_REGR_AVGY) {
    if (OB_FAIL(expand_regr_avg_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand regr avg expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_REGR_SXX || aggr_expr->get_expr_type() == T_FUN_REGR_SYY ||
             aggr_expr->get_expr_type() == T_FUN_REGR_SXY) {
    if (OB_FAIL(expand_regr_s_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand regr s expr", K(ret));
    }
  } else { /*do nothing*/
  }
  return ret;
}

// Premise: (expr1, expr2) neither expr is NULL
// REGR_SLOPE(expr1, expr2) = COVAR_POP(expr1, expr2) / VAR_POP(expr2)
int ObExpandAggregateUtils::expand_regr_slope_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr1 = NULL;
  ObRawExpr* parma_expr2 = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_REGR_SLOPE || aggr_expr->get_real_param_exprs().count() != 2) ||
      OB_ISNULL(parma_expr1 = aggr_expr->get_real_param_exprs().at(0)) ||
      OB_ISNULL(parma_expr2 = aggr_expr->get_real_param_exprs().at(1))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* covar_pop_expr = NULL;
    ObAggFunRawExpr* var_pop_expr = NULL;
    ObConstRawExpr* zero_expr = NULL;
    ObRawExpr* null_expr = NULL;
    ObRawExpr* ne_expr = NULL;
    ObRawExpr* case_when_expr = NULL;
    ObRawExpr* left_div_expr = NULL;
    ObRawExpr* right_div_expr = NULL;
    ObRawExpr* div_expr = NULL;
    ObRawExpr* right_div_case_when_expr = NULL;
    if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_COVAR_POP, covar_pop_expr))) {
      LOG_WARN("failed to create expr", K(ret));
    } else if (OB_FAIL(covar_pop_expr->add_real_param_expr(parma_expr1))) {
      LOG_WARN("fail to add param expr to agg expr", K(ret));
    } else if (OB_FAIL(covar_pop_expr->add_real_param_expr(parma_expr2))) {
      LOG_WARN("fail to add param expr to agg expr", K(ret));
    } else {
      covar_pop_expr->set_expr_level(aggr_expr->get_expr_level());
      if (OB_FAIL(expand_covar_expr(ctx, covar_pop_expr, left_div_expr, new_aggr_items))) {
        LOG_WARN("failed to expand covar expr", K(ret));
      } else if (OB_FAIL(build_special_case_when_expr(
                     *ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr2, case_when_expr))) {
        LOG_WARN("failed to build special case when expr", K(ret));
      } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_VAR_POP, var_pop_expr))) {
        LOG_WARN("failed to create expr", K(ret));
      } else if (OB_FAIL(var_pop_expr->add_real_param_expr(case_when_expr))) {
        LOG_WARN("fail to add param expr to agg expr", K(ret));
      } else {
        var_pop_expr->set_expr_level(aggr_expr->get_expr_level());
        if (OB_FAIL(expand_var_expr(ctx, var_pop_expr, right_div_expr, new_aggr_items))) {
          LOG_WARN("failed to expand var expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_null_expr(*ctx->expr_factory_, null_expr))) {
          LOG_WARN("failed to build null expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx->expr_factory_, ObIntType, 0, zero_expr))) {
          LOG_WARN("failed to build const int expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                       *ctx->expr_factory_, T_OP_NE, right_div_expr, zero_expr, ne_expr))) {
          LOG_WARN("failed to build common binary op expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(
                       *ctx->expr_factory_, ne_expr, right_div_expr, null_expr, right_div_case_when_expr))) {
          LOG_WARN("failed to build case when expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                       *ctx->expr_factory_, T_OP_DIV, left_div_expr, right_div_case_when_expr, div_expr))) {
          LOG_WARN("failed to build common binary op expr", K(ret));
        } else {
          replace_expr = div_expr;
        }
      }
    }
  }
  return ret;
}

// Premise: (expr1, expr2) neither expr is NULL
// REGR_INTERCEPT(expr1, expr2) = AVG(expr1) - REGR_SLOPE(expr1, expr2) * AVG(expr2)
int ObExpandAggregateUtils::expand_regr_intercept_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr1 = NULL;
  ObRawExpr* parma_expr2 = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(
          aggr_expr->get_expr_type() != T_FUN_REGR_INTERCEPT || aggr_expr->get_real_param_exprs().count() != 2) ||
      OB_ISNULL(parma_expr1 = aggr_expr->get_real_param_exprs().at(0)) ||
      OB_ISNULL(parma_expr2 = aggr_expr->get_real_param_exprs().at(1))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* regr_slope_expr = NULL;
    ObAggFunRawExpr* sum_expr1 = NULL;
    ObAggFunRawExpr* sum_expr2 = NULL;
    ObAggFunRawExpr* count_expr1 = NULL;
    ObAggFunRawExpr* count_expr2 = NULL;
    ObRawExpr* case_when_expr1 = NULL;
    ObRawExpr* case_when_expr2 = NULL;
    ObRawExpr* minus_expr = NULL;
    ObRawExpr* multi_expr = NULL;
    ObRawExpr* div_expr1 = NULL;
    ObRawExpr* div_expr2 = NULL;
    ObRawExpr* left_minus_expr = NULL;
    ObRawExpr* right_minus_expr = NULL;
    ObRawExpr* left_multi_expr = NULL;
    if (OB_FAIL(build_special_case_when_expr(
            *ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr1, case_when_expr1))) {
      LOG_WARN("failed to build case when expr", K(ret));
    } else if (OB_FAIL(build_special_case_when_expr(
                   *ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr2, case_when_expr2))) {
      LOG_WARN("failed to build case when expr", K(ret));
    } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_REGR_SLOPE, regr_slope_expr))) {
      LOG_WARN("failed to create expr", K(ret));
    } else if (OB_FAIL(regr_slope_expr->add_real_param_expr(parma_expr1))) {
      LOG_WARN("fail to add param expr to agg expr", K(ret));
    } else if (OB_FAIL(regr_slope_expr->add_real_param_expr(parma_expr2))) {
      LOG_WARN("fail to add param expr to agg expr", K(ret));
    } else {
      regr_slope_expr->set_expr_level(aggr_expr->get_expr_level());
      if (OB_FAIL(expand_regr_slope_expr(ctx, regr_slope_expr, left_multi_expr, new_aggr_items))) {
        LOG_WARN("failed to expand regr slope expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                     *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, case_when_expr1, sum_expr1))) {
        LOG_WARN("failed to build common aggr expr", K(ret));
      } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_expr1))) {
        LOG_WARN("failed to push back aggr item");
      } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                     *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, case_when_expr1, count_expr1))) {
        LOG_WARN("failed to build common aggr expr", K(ret));
      } else if (OB_FAIL(add_aggr_item(new_aggr_items, count_expr1))) {
        LOG_WARN("failed to push back aggr item");
      } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                     *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, case_when_expr2, sum_expr2))) {
        LOG_WARN("failed to build common aggr expr", K(ret));
      } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_expr2))) {
        LOG_WARN("failed to push back aggr item");
      } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                     *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, case_when_expr2, count_expr2))) {
        LOG_WARN("failed to build common aggr expr", K(ret));
      } else if (OB_FAIL(add_aggr_item(new_aggr_items, count_expr2))) {
        LOG_WARN("failed to push back aggr item");
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_DIV, sum_expr1, count_expr1, div_expr1))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_DIV, sum_expr2, count_expr2, div_expr2))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_MUL, left_multi_expr, div_expr2, multi_expr))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_MINUS, div_expr1, multi_expr, minus_expr))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else {
        sum_expr1->set_expr_level(aggr_expr->get_expr_level());
        sum_expr2->set_expr_level(aggr_expr->get_expr_level());
        count_expr1->set_expr_level(aggr_expr->get_expr_level());
        count_expr2->set_expr_level(aggr_expr->get_expr_level());
        replace_expr = minus_expr;
      }
    }
  }
  return ret;
}

// Premise: (expr1, expr2) neither expr is NULL
// REGR_COUNT(expr1, expr2) = COUNT(case expr1 is not null and c2 is not null then expr1 else null end);
int ObExpandAggregateUtils::expand_regr_count_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr1 = NULL;
  ObRawExpr* parma_expr2 = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_REGR_COUNT || aggr_expr->get_real_param_exprs().count() != 2) ||
      OB_ISNULL(parma_expr1 = aggr_expr->get_real_param_exprs().at(0)) ||
      OB_ISNULL(parma_expr2 = aggr_expr->get_real_param_exprs().at(1))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* count_expr = NULL;
    ObRawExpr* case_when_expr = NULL;
    if (OB_FAIL(
            build_special_case_when_expr(*ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr1, case_when_expr))) {
      LOG_WARN("failed to build special case when expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, case_when_expr, count_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, count_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else {
      count_expr->set_expr_level(aggr_expr->get_expr_level());
      replace_expr = count_expr;
    }
  }
  return ret;
}

// Premise: (expr1, expr2) neither expr is NULL
// REGR_R2(expr1, expr2) = if VAR_POP(expr2)  = 0 ==> NULL
//                        if VAR_POP(expr1)  = 0 and VAR_POP(expr2) != 0 ==> 1
//                        if VAR_POP(expr1)  > 0 and  VAR_POP(expr2) != 0 ==> POWER(CORR(expr1,expr),2)
//   ==> case when VAR_POP(expr2) = 0 then NULL else (case when VAR_POP(expr1)  = 0 then 1 else
//   POWER(CORR(expr1,expr2),2));
int ObExpandAggregateUtils::expand_regr_r2_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr1 = NULL;
  ObRawExpr* parma_expr2 = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_REGR_R2 || aggr_expr->get_real_param_exprs().count() != 2) ||
      OB_ISNULL(parma_expr1 = aggr_expr->get_real_param_exprs().at(0)) ||
      OB_ISNULL(parma_expr2 = aggr_expr->get_real_param_exprs().at(1))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* var_pop_expr1 = NULL;
    ObAggFunRawExpr* var_pop_expr2 = NULL;
    ObAggFunRawExpr* corr_expr = NULL;
    ObRawExpr* case_when_expr1 = NULL;
    ObRawExpr* case_when_expr2 = NULL;
    ObConstRawExpr* one_expr = NULL;
    ObConstRawExpr* two_expr = NULL;
    ObConstRawExpr* zero_expr = NULL;
    ObRawExpr* ne_expr = NULL;
    ObRawExpr* case_when_expr = NULL;
    ObRawExpr* null_expr = NULL;
    ObRawExpr* eq_left_expr1 = NULL;
    ObRawExpr* eq_left_expr2 = NULL;
    ObRawExpr* eq_expr1 = NULL;
    ObRawExpr* eq_expr2 = NULL;
    ObRawExpr* power_param_expr = NULL;
    ObSysFunRawExpr* power_expr = NULL;
    if (OB_FAIL(ObRawExprUtils::build_null_expr(*ctx->expr_factory_, null_expr))) {
      LOG_WARN("failed to build null expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx->expr_factory_, ObIntType, 1, one_expr))) {
      LOG_WARN("failed to build const int expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx->expr_factory_, ObIntType, 2, two_expr))) {
      LOG_WARN("failed to build const int expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*ctx->expr_factory_, ObIntType, 0, zero_expr))) {
      LOG_WARN("failed to build const int expr", K(ret));
    } else if (OB_FAIL(build_special_case_when_expr(
                   *ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr1, case_when_expr1))) {
      LOG_WARN("failed to build special case when expr", K(ret));
    } else if (OB_FAIL(build_special_case_when_expr(
                   *ctx->expr_factory_, parma_expr1, parma_expr2, parma_expr2, case_when_expr2))) {
      LOG_WARN("failed to build special case when expr", K(ret));
    } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_VAR_POP, var_pop_expr1))) {
      LOG_WARN("failed to create expr", K(ret));
    } else if (OB_FAIL(var_pop_expr1->add_real_param_expr(case_when_expr1))) {
      LOG_WARN("fail to add param expr to agg expr", K(ret));
    } else {
      var_pop_expr1->set_expr_level(aggr_expr->get_expr_level());
      if (OB_FAIL(expand_var_expr(ctx, var_pop_expr1, eq_left_expr1, new_aggr_items))) {
        LOG_WARN("failed to expand var expr", K(ret));
      } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_VAR_POP, var_pop_expr2))) {
        LOG_WARN("failed to create expr", K(ret));
      } else if (OB_FAIL(var_pop_expr2->add_real_param_expr(case_when_expr2))) {
        LOG_WARN("fail to add param expr to agg expr", K(ret));
      } else {
        var_pop_expr2->set_expr_level(aggr_expr->get_expr_level());
        if (OB_FAIL(expand_var_expr(ctx, var_pop_expr2, eq_left_expr2, new_aggr_items))) {
          LOG_WARN("failed to expand var expr", K(ret));
        } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_CORR, corr_expr))) {
          LOG_WARN("failed to create expr", K(ret));
        } else if (OB_FAIL(corr_expr->add_real_param_expr(parma_expr1))) {
          LOG_WARN("fail to add param expr to agg expr", K(ret));
        } else if (OB_FAIL(corr_expr->add_real_param_expr(parma_expr2))) {
          LOG_WARN("fail to add param expr to agg expr", K(ret));
        } else {
          corr_expr->set_expr_level(aggr_expr->get_expr_level());
          if (OB_FAIL(expand_corr_expr(ctx, corr_expr, power_param_expr, new_aggr_items))) {
            LOG_WARN("failed to expand corr expr", K(ret));
          } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_SYS_POWER, power_expr))) {
            LOG_WARN("failed to create expr", K(ret));
          } else if (OB_FAIL(power_expr->add_param_expr(power_param_expr))) {
            LOG_WARN("failed to add param expr", K(ret));
          } else if (OB_FAIL(power_expr->add_param_expr(two_expr))) {
            LOG_WARN("failed to add param expr", K(ret));
          } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                         *ctx->expr_factory_, T_OP_EQ, eq_left_expr1, zero_expr, eq_expr1))) {
            LOG_WARN("failed to build common binary op expr", K(ret));
          } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(
                         *ctx->expr_factory_, eq_expr1, one_expr, power_expr, case_when_expr2))) {
            LOG_WARN("failed to build case when expr", K(ret));
          } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                         *ctx->expr_factory_, T_OP_EQ, eq_left_expr2, zero_expr, eq_expr2))) {
            LOG_WARN("failed to build common binary op expr", K(ret));
          } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(
                         *ctx->expr_factory_, eq_expr2, null_expr, case_when_expr2, case_when_expr1))) {
            LOG_WARN("failed to build case when expr", K(ret));
          } else {
            replace_expr = case_when_expr1;
          }
        }
      }
    }
  }
  return ret;
}

// Premise: (expr1, expr2) neither expr is NULL
// REGR_AVGX(expr1, expr2) = AVG(expr2);
// REGR_AVGY(expr1, expr2) = AVG(expr1);
int ObExpandAggregateUtils::expand_regr_avg_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr1 = NULL;
  ObRawExpr* parma_expr2 = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY((aggr_expr->get_expr_type() != T_FUN_REGR_AVGX && aggr_expr->get_expr_type() != T_FUN_REGR_AVGY) ||
                  aggr_expr->get_real_param_exprs().count() != 2) ||
      OB_ISNULL(parma_expr1 = aggr_expr->get_real_param_exprs().at(0)) ||
      OB_ISNULL(parma_expr2 = aggr_expr->get_real_param_exprs().at(1))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* sum_expr = NULL;
    ObAggFunRawExpr* count_expr = NULL;
    ObRawExpr* div_expr = NULL;
    ObRawExpr* case_when_expr = NULL;
    ObRawExpr* then_expr = aggr_expr->get_expr_type() == T_FUN_REGR_AVGX ? parma_expr2 : parma_expr1;
    if (OB_FAIL(
            build_special_case_when_expr(*ctx->expr_factory_, parma_expr1, parma_expr2, then_expr, case_when_expr))) {
      LOG_WARN("failed to build special case when expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, case_when_expr, sum_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, case_when_expr, count_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, count_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_DIV, sum_expr, count_expr, div_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else {
      sum_expr->set_expr_level(aggr_expr->get_expr_level());
      count_expr->set_expr_level(aggr_expr->get_expr_level());
      replace_expr = div_expr;
    }
  }
  return ret;
}

// Premise: (expr1, expr2) neither expr is NULL
// REGR_SXX(expr1, expr2) = REGR_COUNT(expr1, expr2) * VAR_POP(expr2)
// REGR_SYY(expr1, expr2) = REGR_COUNT(expr1, expr2) * VAR_POP(expr1)
// REGR_SXY(expr1, expr2) = REGR_COUNT(expr1, expr2) * COVAR_POP(expr1, expr2)
int ObExpandAggregateUtils::expand_regr_s_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr1 = NULL;
  ObRawExpr* parma_expr2 = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY((aggr_expr->get_expr_type() != T_FUN_REGR_SXX && aggr_expr->get_expr_type() != T_FUN_REGR_SYY &&
                      aggr_expr->get_expr_type() != T_FUN_REGR_SXY) ||
                  aggr_expr->get_real_param_exprs().count() != 2) ||
      OB_ISNULL(parma_expr1 = aggr_expr->get_real_param_exprs().at(0)) ||
      OB_ISNULL(parma_expr2 = aggr_expr->get_real_param_exprs().at(1))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* regr_count_expr = NULL;
    ObAggFunRawExpr* var_pop_expr = NULL;
    ObAggFunRawExpr* covar_pop_expr = NULL;
    ObRawExpr* left_multi_expr = NULL;
    ObRawExpr* right_multi_expr = NULL;
    ObRawExpr* multi_expr = NULL;
    ObRawExpr* case_when_expr = NULL;
    if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_REGR_COUNT, regr_count_expr))) {
      LOG_WARN("failed to create expr", K(ret));
    } else if (OB_FAIL(regr_count_expr->add_real_param_expr(parma_expr1))) {
      LOG_WARN("fail to add param expr to agg expr", K(ret));
    } else if (OB_FAIL(regr_count_expr->add_real_param_expr(parma_expr2))) {
      LOG_WARN("fail to add param expr to agg expr", K(ret));
    } else {
      regr_count_expr->set_expr_level(aggr_expr->get_expr_level());
      if (OB_FAIL(expand_regr_count_expr(ctx, regr_count_expr, left_multi_expr, new_aggr_items))) {
        LOG_WARN("failed to expand regr count expr", K(ret));
      } else if (aggr_expr->get_expr_type() == T_FUN_REGR_SXX || aggr_expr->get_expr_type() == T_FUN_REGR_SYY) {
        ObRawExpr* then_expr = aggr_expr->get_expr_type() == T_FUN_REGR_SXX ? parma_expr2 : parma_expr1;
        if (OB_FAIL(build_special_case_when_expr(
                *ctx->expr_factory_, parma_expr1, parma_expr2, then_expr, case_when_expr))) {
          LOG_WARN("failed to build special case when expr", K(ret));
        } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_VAR_POP, var_pop_expr))) {
          LOG_WARN("failed to create expr", K(ret));
        } else if (OB_FAIL(var_pop_expr->add_real_param_expr(case_when_expr))) {
          LOG_WARN("fail to add param expr to agg expr", K(ret));
        } else {
          var_pop_expr->set_expr_level(aggr_expr->get_expr_level());
          if (OB_FAIL(expand_var_expr(ctx, var_pop_expr, right_multi_expr, new_aggr_items))) {
            LOG_WARN("failed to expand var expr", K(ret));
          } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                         *ctx->expr_factory_, T_OP_MUL, left_multi_expr, right_multi_expr, multi_expr))) {
            LOG_WARN("failed to build common binary op expr", K(ret));
          } else {
            replace_expr = multi_expr;
          }
        }
      } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_COVAR_POP, covar_pop_expr))) {
        LOG_WARN("failed to create expr", K(ret));
      } else if (OB_FAIL(covar_pop_expr->add_real_param_expr(parma_expr1))) {
        LOG_WARN("fail to add param expr to agg expr", K(ret));
      } else if (OB_FAIL(covar_pop_expr->add_real_param_expr(parma_expr2))) {
        LOG_WARN("fail to add param expr to agg expr", K(ret));
      } else {
        covar_pop_expr->set_expr_level(aggr_expr->get_expr_level());
        if (OB_FAIL(expand_covar_expr(ctx, covar_pop_expr, right_multi_expr, new_aggr_items))) {
          LOG_WARN("failed to expand covar expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                       *ctx->expr_factory_, T_OP_MUL, left_multi_expr, right_multi_expr, multi_expr))) {
          LOG_WARN("failed to build common binary op expr", K(ret));
        } else {
          replace_expr = multi_expr;
        }
      }
    }
  }
  return ret;
}

bool ObExpandAggregateUtils::is_valid_aggr_type(const ObItemType aggr_type)
{
  return aggr_type == T_FUN_CORR || aggr_type == T_FUN_COVAR_POP || aggr_type == T_FUN_COVAR_SAMP ||
         aggr_type == T_FUN_VAR_POP || aggr_type == T_FUN_VAR_SAMP || aggr_type == T_FUN_REGR_SLOPE ||
         aggr_type == T_FUN_REGR_INTERCEPT || aggr_type == T_FUN_REGR_COUNT || aggr_type == T_FUN_REGR_R2 ||
         aggr_type == T_FUN_REGR_AVGX || aggr_type == T_FUN_REGR_AVGY || aggr_type == T_FUN_REGR_SXX ||
         aggr_type == T_FUN_REGR_SYY || aggr_type == T_FUN_REGR_SXY || aggr_type == T_FUN_KEEP_AVG ||
         aggr_type == T_FUN_KEEP_STDDEV || aggr_type == T_FUN_KEEP_VARIANCE || aggr_type == T_FUN_AVG ||
         aggr_type == T_FUN_VARIANCE || aggr_type == T_FUN_STDDEV || aggr_type == T_FUN_STDDEV_POP ||
         aggr_type == T_FUN_STDDEV_SAMP;
}

bool ObExpandAggregateUtils::is_regr_expr_type(const ObItemType aggr_type)
{
  return aggr_type == T_FUN_REGR_SLOPE || aggr_type == T_FUN_REGR_INTERCEPT || aggr_type == T_FUN_REGR_COUNT ||
         aggr_type == T_FUN_REGR_R2 || aggr_type == T_FUN_REGR_AVGX || aggr_type == T_FUN_REGR_AVGY ||
         aggr_type == T_FUN_REGR_SXX || aggr_type == T_FUN_REGR_SYY || aggr_type == T_FUN_REGR_SXY;
}

int ObExpandAggregateUtils::build_special_case_when_expr(ObRawExprFactory& expr_factory, ObRawExpr* param_expr1,
    ObRawExpr* param_expr2, ObRawExpr* then_expr, ObRawExpr*& case_when_expr)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(param_expr1) || OB_ISNULL(param_expr2) || OB_ISNULL(then_expr)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid argument", K(param_expr1), K(param_expr2), K(then_expr), K(ret));
  } else {
    ObRawExpr* null_expr = NULL;
    ObRawExpr* false_expr = NULL;
    ObRawExpr* is_not_expr1 = NULL;
    ObRawExpr* is_not_expr2 = NULL;
    ObRawExpr* and_expr = NULL;
    case_when_expr = NULL;
    if (OB_FAIL(ObRawExprUtils::build_null_expr(expr_factory, null_expr))) {
      LOG_WARN("failed to build null expr", K(ret));
    } else if (OB_FAIL(
                   ObRawExprUtils::build_const_bool_expr(&expr_factory, false_expr, false))) {
      LOG_WARN("failed to build const bool expr", K(ret));
    } else if (OB_FAIL(
                   ObRawExprUtils::build_is_not_expr(expr_factory, param_expr1, null_expr, false_expr, is_not_expr1))) {
      LOG_WARN("failed to build is not expr", K(ret));
    } else if (OB_FAIL(
                   ObRawExprUtils::build_is_not_expr(expr_factory, param_expr2, null_expr, false_expr, is_not_expr2))) {
      LOG_WARN("failed to build is not expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   expr_factory, T_OP_AND, is_not_expr1, is_not_expr2, and_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(
                   expr_factory, and_expr, then_expr, null_expr, case_when_expr))) {
      LOG_WARN("failed to build case when expr", K(ret));
    } else { /*do nothing*/
    }
  }
  return ret;
}

int ObExpandAggregateUtils::expand_keep_aggr_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(aggr_expr) || OB_UNLIKELY(!is_keep_aggr_type(aggr_expr->get_expr_type()))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else if (aggr_expr->get_expr_type() == T_FUN_KEEP_AVG) {
    if (OB_FAIL(expand_keep_avg_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand keep avg expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_KEEP_STDDEV) {
    if (OB_FAIL(expand_keep_stddev_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand keep stddev expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_KEEP_VARIANCE) {
    if (OB_FAIL(expand_keep_variance_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand keep variance expr", K(ret));
    }
  } else { /*do nothing*/
  }
  return ret;
}

/*avg(expr) keep(...) <==> sum(expr) keep(...) / count(expr) keep(...)
 */
int ObExpandAggregateUtils::expand_keep_avg_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_KEEP_AVG || aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* keep_sum_expr = NULL;
    ObAggFunRawExpr* keep_count_expr = NULL;
    ObRawExpr* div_expr = NULL;
    const ObIArray<OrderItem>& order_items = aggr_expr->get_order_items();
    if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
            *ctx->expr_factory_, ctx->session_info_, T_FUN_KEEP_SUM, parma_expr, keep_sum_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(append(keep_sum_expr->get_order_items_for_update(), order_items))) {
      LOG_WARN("fail to append order items", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, keep_sum_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_KEEP_COUNT, parma_expr, keep_count_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(append(keep_count_expr->get_order_items_for_update(), order_items))) {
      LOG_WARN("fail to append order items", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, keep_count_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_DIV, keep_sum_expr, keep_count_expr, div_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else {
      keep_sum_expr->set_expr_level(aggr_expr->get_expr_level());
      keep_count_expr->set_expr_level(aggr_expr->get_expr_level());
      replace_expr = div_expr;
    }
  }
  return ret;
}

// variance:
// D(x) <==> if count(x) = 1 ==> (SUM(x*x) - SUM(x)* SUM(x)/ COUNT(x)) / (1) = 0
//        if count(x) > 1 ==> var_samp(x) ==> (SUM(x*x) - SUM(x)* SUM(x)/ COUNT(x)) / (COUNT(x) - 1)
int ObExpandAggregateUtils::expand_keep_variance_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(
          aggr_expr->get_expr_type() != T_FUN_KEEP_VARIANCE || aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObRawExpr* multi_expr = NULL;
    ObRawExpr* multi_keep_sum_expr = NULL;
    ObAggFunRawExpr* keep_sum_expr = NULL;
    ObAggFunRawExpr* keep_sum_product_expr = NULL;
    ObAggFunRawExpr* keep_count_expr = NULL;
    ObRawExpr* div_expr = NULL;
    ObRawExpr* minus_expr = NULL;
    ObRawExpr* keep_count_minus_expr = NULL;
    ObRawExpr* div_minus_expr = NULL;
    ObConstRawExpr* one_expr = NULL;
    ObRawExpr* eq_expr = NULL;
    ObRawExpr* case_when_expr = NULL;
    const ObIArray<OrderItem>& order_items = aggr_expr->get_order_items();
    if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
            *ctx->expr_factory_, ctx->session_info_, T_FUN_KEEP_COUNT, parma_expr, keep_count_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(append(keep_count_expr->get_order_items_for_update(), order_items))) {
      LOG_WARN("fail to append order items", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, keep_count_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_const_number_expr(
                   *ctx->expr_factory_, ObNumberType, number::ObNumber::get_positive_one(), one_expr))) {
      LOG_WARN("failed to build const number expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_EQ, keep_count_expr, one_expr, eq_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MUL, parma_expr, parma_expr, multi_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_KEEP_SUM, parma_expr, keep_sum_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(append(keep_sum_expr->get_order_items_for_update(), order_items))) {
      LOG_WARN("fail to append order items", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, keep_sum_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MUL, keep_sum_expr, keep_sum_expr, multi_keep_sum_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_KEEP_SUM, multi_expr, keep_sum_product_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(append(keep_sum_product_expr->get_order_items_for_update(), order_items))) {
      LOG_WARN("fail to append order items", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, keep_sum_product_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_DIV, multi_keep_sum_expr, keep_count_expr, div_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MINUS, keep_count_expr, one_expr, keep_count_minus_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_MINUS, keep_sum_product_expr, div_expr, minus_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(
                   *ctx->expr_factory_, eq_expr, one_expr, keep_count_minus_expr, case_when_expr))) {
      LOG_WARN("failed to build case when expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_DIV, minus_expr, case_when_expr, div_minus_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));

    } else {
      keep_sum_expr->set_expr_level(aggr_expr->get_expr_level());
      keep_sum_product_expr->set_expr_level(aggr_expr->get_expr_level());
      keep_count_expr->set_expr_level(aggr_expr->get_expr_level());
      replace_expr = div_minus_expr;
    }
  }
  return ret;
}

// stddev(expr) <==> sqrt(variance(expr))
int ObExpandAggregateUtils::expand_keep_stddev_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_KEEP_STDDEV || aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObSysFunRawExpr* sqrt_expr = NULL;
    ObRawExpr* sqrt_param_expr = NULL;
    ObAggFunRawExpr* keep_variance_expr = NULL;
    const ObIArray<OrderItem>& order_items = aggr_expr->get_order_items();
    if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
            *ctx->expr_factory_, ctx->session_info_, T_FUN_KEEP_VARIANCE, parma_expr, keep_variance_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(append(keep_variance_expr->get_order_items_for_update(), order_items))) {
      LOG_WARN("fail to append order items", K(ret));
    } else {
      keep_variance_expr->set_expr_level(aggr_expr->get_expr_level());
      if (OB_FAIL(expand_keep_variance_expr(ctx, keep_variance_expr, sqrt_param_expr, new_aggr_items))) {
        LOG_WARN("fail to expand keep variance expr", K(ret));
      } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_SYS_SQRT, sqrt_expr))) {
        LOG_WARN("failed to crate sqrt expr", K(ret));
      } else if (OB_ISNULL(sqrt_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("add expr is null", K(ret), K(sqrt_expr));
      } else if (OB_FAIL(sqrt_expr->add_param_expr(sqrt_param_expr))) {
        LOG_WARN("add text expr to add expr failed", K(ret));
      } else {
        ObString func_name = ObString::make_string("sqrt");
        sqrt_expr->set_func_name(func_name);
        replace_expr = sqrt_expr;
      }
    }
  }
  return ret;
}

int ObExpandAggregateUtils::expand_common_aggr_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(aggr_expr) || OB_UNLIKELY(!is_common_aggr_type(aggr_expr->get_expr_type()))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else if (aggr_expr->get_expr_type() == T_FUN_AVG) {
    if (OB_FAIL(expand_avg_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand avg expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_STDDEV) {
    if (OB_FAIL(expand_stddev_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand stddev expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_VARIANCE) {
    if (share::is_oracle_mode() && OB_FAIL(expand_oracle_variance_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand oracle variance expr", K(ret));
    } else if (share::is_mysql_mode() &&
               OB_FAIL(expand_mysql_variance_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand mysql variance expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_STDDEV_POP) {
    if (OB_FAIL(expand_stddev_pop_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand stddev expr", K(ret));
    }
  } else if (aggr_expr->get_expr_type() == T_FUN_STDDEV_SAMP) {
    if (OB_FAIL(expand_stddev_samp_expr(ctx, aggr_expr, replace_expr, new_aggr_items))) {
      LOG_WARN("failed to expand stddev expr", K(ret));
    }
  } else { /*do nothing*/
  }
  return ret;
}

/*avg(expr) keep(...) <==> sum(expr) keep(...) / count(expr) keep(...)
 */
int ObExpandAggregateUtils::expand_avg_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr, ObRawExpr*& replace_expr,
    ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_AVG || aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* sum_expr = NULL;
    ObAggFunRawExpr* count_expr = NULL;
    ObRawExpr* div_expr = NULL;
    if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
            *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, parma_expr, sum_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else {
      sum_expr->set_expr_level(aggr_expr->get_expr_level());
      sum_expr->set_param_distinct(aggr_expr->is_param_distinct());
      if (OB_FAIL(add_aggr_item(new_aggr_items, sum_expr))) {
        LOG_WARN("failed to push back aggr item");
      } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                     *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, parma_expr, count_expr))) {
        LOG_WARN("failed to build common aggr expr", K(ret));
      } else {
        count_expr->set_expr_level(aggr_expr->get_expr_level());
        count_expr->set_param_distinct(aggr_expr->is_param_distinct());
        if (OB_FAIL(add_aggr_item(new_aggr_items, count_expr))) {
          LOG_WARN("failed to push back aggr item");
        } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                       *ctx->expr_factory_, T_OP_AGG_DIV, sum_expr, count_expr, div_expr))) {
          LOG_WARN("failed to build common binary op expr", K(ret));
        } else {
          replace_expr = div_expr;
        }
      }
    }
  }
  return ret;
}

// oracle variance:
// D(x) <==> if count(x) = 1 ==> (SUM(x*x) - SUM(x)* SUM(x)/ COUNT(x)) / (1) = 0
//        if count(x) > 1 ==> var_samp(x) ==> (SUM(x*x) - SUM(x)* SUM(x)/ COUNT(x)) / (COUNT(x) - 1)
int ObExpandAggregateUtils::expand_oracle_variance_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_VARIANCE || aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObRawExpr* multi_expr = NULL;
    ObRawExpr* multi_sum_expr = NULL;
    ObAggFunRawExpr* sum_expr = NULL;
    ObAggFunRawExpr* sum_product_expr = NULL;
    ObAggFunRawExpr* count_expr = NULL;
    ObRawExpr* div_expr = NULL;
    ObRawExpr* minus_expr = NULL;
    ObRawExpr* count_minus_expr = NULL;
    ObRawExpr* div_minus_expr = NULL;
    ObConstRawExpr* one_expr = NULL;  // oracle mode count result type is number
    ObRawExpr* eq_expr = NULL;
    ObRawExpr* case_when_expr = NULL;
    if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
            *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, parma_expr, count_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else {
      count_expr->set_param_distinct(aggr_expr->is_param_distinct());
      count_expr->set_expr_level(aggr_expr->get_expr_level());
      if (OB_FAIL(add_aggr_item(new_aggr_items, count_expr))) {
        LOG_WARN("failed to push back aggr item");
      } else if (OB_FAIL(ObRawExprUtils::build_const_number_expr(
                     *ctx->expr_factory_, ObNumberType, number::ObNumber::get_positive_one(), one_expr))) {
        LOG_WARN("failed to build const number expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_EQ, count_expr, one_expr, eq_expr))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                     *ctx->expr_factory_, T_OP_MUL, parma_expr, parma_expr, multi_expr))) {
        LOG_WARN("failed to build common binary op expr", K(ret));
      } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                     *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, parma_expr, sum_expr))) {
        LOG_WARN("failed to build common aggr expr", K(ret));
      } else {
        sum_expr->set_expr_level(aggr_expr->get_expr_level());
        sum_expr->set_param_distinct(aggr_expr->is_param_distinct());
        if (OB_FAIL(add_aggr_item(new_aggr_items, sum_expr))) {
          LOG_WARN("failed to push back aggr item");
        } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                       *ctx->expr_factory_, T_OP_MUL, sum_expr, sum_expr, multi_sum_expr))) {
          LOG_WARN("failed to build common binary op expr", K(ret));
        } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                       *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, multi_expr, sum_product_expr))) {
          LOG_WARN("failed to build common aggr expr", K(ret));
        } else {
          sum_product_expr->set_expr_level(aggr_expr->get_expr_level());
          sum_product_expr->set_param_distinct(aggr_expr->is_param_distinct());
          if (OB_FAIL(add_aggr_item(new_aggr_items, sum_product_expr))) {
            LOG_WARN("failed to push back aggr item");
          } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                         *ctx->expr_factory_, T_OP_DIV, multi_sum_expr, count_expr, div_expr))) {
            LOG_WARN("failed to build common binary op expr", K(ret));
          } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                         *ctx->expr_factory_, T_OP_MINUS, count_expr, one_expr, count_minus_expr))) {
            LOG_WARN("failed to build common binary op expr", K(ret));
          } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                         *ctx->expr_factory_, T_OP_MINUS, sum_product_expr, div_expr, minus_expr))) {
            LOG_WARN("failed to build common binary op expr", K(ret));
          } else if (OB_FAIL(ObRawExprUtils::build_case_when_expr(
                         *ctx->expr_factory_, eq_expr, one_expr, count_minus_expr, case_when_expr))) {
          } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                         *ctx->expr_factory_, T_OP_DIV, minus_expr, case_when_expr, div_minus_expr))) {
            LOG_WARN("failed to build common binary op expr", K(ret));
          } else {
            replace_expr = div_minus_expr;
          }
        }
      }
    }
  }
  return ret;
}

// mysql variance: avg(expr1*expr1) - avg(expr1)*avg(expr1)
int ObExpandAggregateUtils::expand_mysql_variance_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY((aggr_expr->get_expr_type() != T_FUN_VARIANCE && aggr_expr->get_expr_type() != T_FUN_VAR_POP) ||
                  aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObAggFunRawExpr* sum_expr = NULL;
    ObRawExpr* cast_sum_expr = NULL;
    ObAggFunRawExpr* count_expr = NULL;
    ObAggFunRawExpr* sum_product_expr = NULL;
    ObRawExpr* cast_sum_product_expr = NULL;
    ObAggFunRawExpr* count_product_expr = NULL;
    ObRawExpr* minus_expr = NULL;
    ObRawExpr* multi_expr = NULL;
    ObRawExpr* multi_sum_expr = NULL;
    ObRawExpr* multi_count_expr = NULL;
    ObRawExpr* div_expr = NULL;
    ObRawExpr* div_multi_expr = NULL;
    ObRawExpr* cast_minus_expr = NULL;
    ObExprResType dst_type;
    dst_type.set_number();
    dst_type.set_scale(ObAccuracy::MAX_ACCURACY2[MYSQL_MODE][ObNumberType].get_scale());
    dst_type.set_precision(ObAccuracy::MAX_ACCURACY2[MYSQL_MODE][ObNumberType].get_precision());
    ObExprResType result_type;
    result_type.set_double();
    result_type.set_scale(ObAccuracy(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET).get_scale());
    result_type.set_precision(ObAccuracy(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET).get_precision());
    if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
            *ctx->expr_factory_, T_OP_AGG_MUL, parma_expr, parma_expr, multi_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, parma_expr, sum_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(add_cast_expr(ctx, sum_expr, dst_type, cast_sum_expr))) {
      LOG_WARN("failed to add cast expr");
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_SUM, multi_expr, sum_product_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, sum_product_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(add_cast_expr(ctx, sum_product_expr, dst_type, cast_sum_product_expr))) {
      LOG_WARN("failed to add cast expr");
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, parma_expr, count_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, count_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
                   *ctx->expr_factory_, ctx->session_info_, T_FUN_COUNT, multi_expr, count_product_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else if (OB_FAIL(add_aggr_item(new_aggr_items, count_product_expr))) {
      LOG_WARN("failed to push back aggr item");
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_AGG_MUL, cast_sum_expr, cast_sum_expr, multi_sum_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_AGG_MUL, count_expr, count_expr, multi_count_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_AGG_DIV, multi_sum_expr, multi_count_expr, div_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_AGG_DIV, cast_sum_product_expr, count_product_expr, div_multi_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(ObRawExprUtils::build_common_binary_op_expr(
                   *ctx->expr_factory_, T_OP_AGG_MINUS, div_multi_expr, div_expr, minus_expr))) {
      LOG_WARN("failed to build common binary op expr", K(ret));
    } else if (OB_FAIL(add_cast_expr(ctx, minus_expr, result_type, cast_minus_expr))) {
      LOG_WARN("failed to add cast expr");
    } else {
      sum_expr->set_expr_level(aggr_expr->get_expr_level());
      count_expr->set_expr_level(aggr_expr->get_expr_level());
      sum_product_expr->set_expr_level(aggr_expr->get_expr_level());
      count_product_expr->set_expr_level(aggr_expr->get_expr_level());
      replace_expr = cast_minus_expr;
    }
  }
  return ret;
}

// stddev(expr) <==> sqrt(variance(expr))
int ObExpandAggregateUtils::expand_stddev_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_STDDEV || aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObSysFunRawExpr* sqrt_expr = NULL;
    ObRawExpr* sqrt_param_expr = NULL;
    ObAggFunRawExpr* variance_expr = NULL;
    if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
            *ctx->expr_factory_, ctx->session_info_, T_FUN_VARIANCE, parma_expr, variance_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else {
      variance_expr->set_expr_level(aggr_expr->get_expr_level());
      variance_expr->set_param_distinct(aggr_expr->is_param_distinct());
      if (share::is_oracle_mode() &&
          OB_FAIL(expand_oracle_variance_expr(ctx, variance_expr, sqrt_param_expr, new_aggr_items))) {
        LOG_WARN("fail to expand oracle variance expr", K(ret));
      } else if (share::is_mysql_mode() &&
                 OB_FAIL(expand_mysql_variance_expr(ctx, variance_expr, sqrt_param_expr, new_aggr_items))) {
        LOG_WARN("fail to expand mysql variance expr", K(ret));
      } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_SYS_SQRT, sqrt_expr))) {
        LOG_WARN("failed to crate sqrt expr", K(ret));
      } else if (OB_ISNULL(sqrt_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("add expr is null", K(ret), K(sqrt_expr));
      } else if (OB_FAIL(sqrt_expr->add_param_expr(sqrt_param_expr))) {
        LOG_WARN("add text expr to add expr failed", K(ret));
      } else {
        ObString func_name = ObString::make_string("sqrt");
        sqrt_expr->set_func_name(func_name);
        replace_expr = sqrt_expr;
      }
    }
  }
  return ret;
}

// stddev_pop(expr) <==> sqrt(var_pop(expr))
int ObExpandAggregateUtils::expand_stddev_pop_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_STDDEV_POP || aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObSysFunRawExpr* sqrt_expr = NULL;
    ObRawExpr* sqrt_param_expr = NULL;
    ObAggFunRawExpr* var_expr = NULL;
    if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
            *ctx->expr_factory_, ctx->session_info_, T_FUN_VAR_POP, parma_expr, var_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else {
      var_expr->set_expr_level(aggr_expr->get_expr_level());
      if (OB_FAIL(expand_var_expr(ctx, var_expr, sqrt_param_expr, new_aggr_items))) {
        LOG_WARN("fail to expand keep variance expr", K(ret));
      } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_SYS_SQRT, sqrt_expr))) {
        LOG_WARN("failed to crate sqrt expr", K(ret));
      } else if (OB_ISNULL(sqrt_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("add expr is null", K(ret), K(sqrt_expr));
      } else if (OB_FAIL(sqrt_expr->add_param_expr(sqrt_param_expr))) {
        LOG_WARN("add text expr to add expr failed", K(ret));
      } else {
        ObString func_name = ObString::make_string("sqrt");
        sqrt_expr->set_func_name(func_name);
        replace_expr = sqrt_expr;
      }
    }
  }
  return ret;
}

// stddev_samp(expr) <==> sqrt(var_samp(expr))
int ObExpandAggregateUtils::expand_stddev_samp_expr(ObTransformerCtx* ctx, ObAggFunRawExpr* aggr_expr,
    ObRawExpr*& replace_expr, ObIArray<ObAggFunRawExpr*>& new_aggr_items)
{
  int ret = OB_SUCCESS;
  ObRawExpr* parma_expr = NULL;
  if (OB_ISNULL(aggr_expr) || OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) ||
      OB_UNLIKELY(aggr_expr->get_expr_type() != T_FUN_STDDEV_SAMP || aggr_expr->get_real_param_exprs().count() != 1) ||
      OB_ISNULL(parma_expr = aggr_expr->get_real_param_exprs().at(0))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(aggr_expr), K(ctx));
  } else {
    ObSysFunRawExpr* sqrt_expr = NULL;
    ObRawExpr* sqrt_param_expr = NULL;
    ObAggFunRawExpr* var_expr = NULL;
    if (OB_FAIL(ObRawExprUtils::build_common_aggr_expr(
            *ctx->expr_factory_, ctx->session_info_, T_FUN_VAR_SAMP, parma_expr, var_expr))) {
      LOG_WARN("failed to build common aggr expr", K(ret));
    } else {
      var_expr->set_expr_level(aggr_expr->get_expr_level());
      if (OB_FAIL(expand_var_expr(ctx, var_expr, sqrt_param_expr, new_aggr_items))) {
        LOG_WARN("fail to expand keep variance expr", K(ret));
      } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_SYS_SQRT, sqrt_expr))) {
        LOG_WARN("failed to crate sqrt expr", K(ret));
      } else if (OB_ISNULL(sqrt_expr)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("add expr is null", K(ret), K(sqrt_expr));
      } else if (OB_FAIL(sqrt_expr->add_param_expr(sqrt_param_expr))) {
        LOG_WARN("add text expr to add expr failed", K(ret));
      } else {
        ObString func_name = ObString::make_string("sqrt");
        sqrt_expr->set_func_name(func_name);
        replace_expr = sqrt_expr;
      }
    }
  }
  return ret;
}

int ObExpandAggregateUtils::add_cast_expr(
    ObTransformerCtx* ctx, ObRawExpr* expr, const ObExprResType& dst_type, ObRawExpr*& new_expr)
{
  int ret = OB_SUCCESS;
  ObSysFunRawExpr* cast_expr = NULL;
  if (OB_ISNULL(expr) || OB_ISNULL(ctx)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(expr), K(ctx));
  } else if (OB_FAIL(ObRawExprUtils::create_cast_expr(
                 *ctx->expr_factory_, expr, dst_type, cast_expr, ctx->session_info_))) {
    LOG_WARN("failed to add cast expr", K(ret));
  } else if (OB_ISNULL(cast_expr)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(cast_expr));
  } else {
    new_expr = cast_expr;
  }
  return ret;
}

int ObExpandAggregateUtils::add_win_exprs(
    ObSelectStmt* select_stmt, ObIArray<ObRawExpr*>& replace_exprs, ObIArray<ObWinFunRawExpr*>& new_win_exprs)
{
  int ret = OB_SUCCESS;
  if (OB_ISNULL(select_stmt)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("get unexpected null", K(ret), K(select_stmt));
  } else if (replace_exprs.count() > 0 && new_win_exprs.count() > 0) {
    select_stmt->get_window_func_exprs().reset();
    for (int64_t i = 0; OB_SUCC(ret) && i < new_win_exprs.count(); ++i) {
      ObWinFunRawExpr* win_expr = NULL;
      if (OB_ISNULL(new_win_exprs.at(i))) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("get unexpected null", K(ret), K(new_win_exprs.at(i)));
      } else if (OB_ISNULL(win_expr = select_stmt->get_same_win_func_item(new_win_exprs.at(i)))) {
        if (OB_FAIL(select_stmt->add_window_func_expr(new_win_exprs.at(i)))) {
          LOG_WARN("failed to add window func expr", K(ret));
        }
      } else {
        for (int64_t j = 0; OB_SUCC(ret) && j < replace_exprs.count(); ++j) {
          if (ObRawExprUtils::replace_ref_column(replace_exprs.at(j), new_win_exprs.at(i), win_expr)) {
            LOG_WARN("failed to replace ref column.", K(ret));
          }
        }
      }
    }
  }
  return ret;
}

}  // namespace sql
}  // namespace oceanbase
